package edu.umd.cs.mouseprecision;

import java.awt.*;
import java.awt.event.*;
import java.io.File;
import java.util.LinkedList;

import javax.swing.*;
import javax.swing.filechooser.FileFilter;

import edu.umd.cs.mouseprecision.TaskCanvas.TaskType;
import edu.umd.cs.piccolo.PCanvas;
import edu.umd.cs.piccolox.PFrame;

import static edu.umd.cs.mouseprecision.TaskCanvas.TaskType.*;

public class MainJFrame extends JFrame implements ActionListener{

	
	JMenuBar menuBar;
	
	JMenu menuExperiment;
	JMenuItem itemStartAll;
	JMenuItem itemStartTrainingTask;
	JMenuItem itemStartSquareTask;
	JMenuItem itemStartDiagonalTask;
	JMenuItem itemStartRoundTask;
	JMenuItem itemExitApplication;
	
	
	JMenu menuAnalysis;
	JMenuItem itemOpenData;
	
	
	TaskCanvas taskCanvas;
	
	/**
	 * internal flag: true if all tasks started
	 */
	boolean allTasksStarted = false;
	LinkedList<TaskType> alreadyExecutedTasks;
	
	public MainJFrame(){
		
		this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
	
		try {
			UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel");
		}catch (Exception e){
			System.out.println("Windows look and feel not supported, changing to standard OS/Java look and feel.");
		}
		
		//all swing stuff in this method
		initializeUI();
		
		//Initial size: full screen
		Insets insets = Toolkit.getDefaultToolkit().getScreenInsets(getGraphicsConfiguration());
		Dimension size = Toolkit.getDefaultToolkit().getScreenSize();
		size.width -= insets.left + insets.right;
		size.height -= insets.top + insets.bottom;
		setSize(size);
		
		//task trace for executing multiple tasks
		alreadyExecutedTasks = new LinkedList<TaskType>();
		
	}


	private void initializeUI() {
		menuBar = new JMenuBar();
		
		menuExperiment = new JMenu("Experiment");
		itemStartAll = new JMenuItem("Start Experiment (all Tasks)");
		itemStartAll.addActionListener(this);
		itemStartTrainingTask = new JMenuItem("Start Training Task");
		itemStartTrainingTask.addActionListener(this);
		itemStartSquareTask = new JMenuItem("Start Square Task");
		itemStartSquareTask.addActionListener(this);
		itemStartDiagonalTask = new JMenuItem("Start Diagonal Task");
		itemStartDiagonalTask.addActionListener(this);
		itemStartRoundTask = new JMenuItem("Start Round Task");
		itemStartRoundTask.addActionListener(this);
		itemExitApplication = new JMenuItem("Exit");
		itemExitApplication.addActionListener(this);
		menuExperiment.add(itemStartAll);
		menuExperiment.addSeparator();
		menuExperiment.add(itemStartTrainingTask);
		menuExperiment.add(itemStartSquareTask);
		menuExperiment.add(itemStartDiagonalTask);
		menuExperiment.add(itemStartRoundTask);
		menuExperiment.addSeparator();
		menuExperiment.add(itemExitApplication);
		menuBar.add(menuExperiment);
		
		menuAnalysis = new JMenu("Analysis");
		itemOpenData = new JMenuItem("Open Data File...");
		itemOpenData.addActionListener(this);
		menuAnalysis.add(itemOpenData);
		menuBar.add(menuAnalysis);
		
		this.setJMenuBar(menuBar);
		
		
		
	}


	public void setMouseInside(boolean inside) {
		if(inside)
			this.setTitle("MOUSE: inside");
		else
			this.setTitle("MOUSE: outside");
		
	}


	@Override
	public void actionPerformed(ActionEvent event) {
		if(event.getSource()==itemStartAll){
			allTasksStarted=true;
			alreadyExecutedTasks.clear();
			//initiates the call for the next task
			startNextTask();
		}
		if(event.getSource()==itemStartTrainingTask){
			startNewTask(TaskCanvas.TaskType.TRAIN);
		}
		if(event.getSource()==itemStartSquareTask){
			startNewTask(TaskCanvas.TaskType.SQUARE);
		}
		if(event.getSource()==itemStartDiagonalTask){
			startNewTask(TaskCanvas.TaskType.DIAGONAL);
		}
		if(event.getSource()==itemStartRoundTask){
			startNewTask(TaskCanvas.TaskType.ROUND);
		}
		
		if(event.getSource()==itemOpenData){
			//Create a file chooser
			final JFileChooser fc = new JFileChooser(".");
			fc.setFileFilter(new  FileFilter(){
				@Override
				public boolean accept(File f) {
					if(f.getName().endsWith(".data") || f.isDirectory())
						return true;
					else
						return false;
				}

				@Override
				public String getDescription() {
					// TODO Auto-generated method stub
					return null;
				}
			});
			
			
			//In response to a button click:
			int returnVal = fc.showOpenDialog(this);
			
			// blocks here until file has been chosen
			
			//read file into DataFile object
			if(fc.getSelectedFile()!=null){
				this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
				DataFile f = new DataFile(fc.getSelectedFile().getPath());
				startNewTask(f.getTaskType());
				
				taskCanvas.setGonePathPoints(f.getTraveledPoints());
				taskCanvas.setGonePathNextPoint(f.getTraveledPoints().length);
				taskCanvas.makePathViolationsVisible();
				taskCanvas.makeTraveledPathVisible();
				this.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
			}
			
			
			

		}
		
		if(event.getSource()==itemExitApplication){
			System.exit(0);
		}
		
	}

	/**
	 * Starts a new task of type taskType.
	 * @param taskType
	 */
	private void startNewTask(TaskType taskType) {
		taskCanvas = new TaskCanvas(this,taskType);
		this.getContentPane().removeAll();
		this.getContentPane().add(taskCanvas, BorderLayout.CENTER);
		this.getContentPane().validate();
	}
	
	/**
	 * Called by taskCanvas when task is over.
	 */
	public void taskFinished(){
		//Show info dialog
		if(allTasksStarted && alreadyExecutedTasks.size()==TaskType.values().length){
			JOptionPane.showMessageDialog(
					this, 
					"You completed the task sucessfully." +
					"\n\nThis was the last task." +
					"\n\nPlease inform the instructor that you completed all tasks.", 
					"Task Completed", 
					JOptionPane.INFORMATION_MESSAGE);
		
		}
		else{
			JOptionPane.showMessageDialog(
					this, 
					"You completed the task sucessfully." +
					"\n\nPlease take a short break to ralax (up to one minute)." +
					"\n\nWhen you are done click OK to proceed to the next task.", 
					"Task Completed", 
					JOptionPane.INFORMATION_MESSAGE);
		
		}
		//starts next task when user started all tasks
		startNextTask();
	}
	
	/**
	 * Starts next task if there are waiting tasks.
	 * Random selection according to experiment layout.
	 */
	private void startNextTask(){
		
		if(allTasksStarted){
			//always start with training task
			if(alreadyExecutedTasks.size() == 0){
				showInstructionsDialog();
				startNewTask(TRAIN); 
				alreadyExecutedTasks.add(TRAIN);
			}
			//all tasks have been executed
			else if(alreadyExecutedTasks.size() == TaskType.values().length){
				allTasksStarted=false;
				return;
			}
			//still non executed tasks left
			else{
				//all task types in one pot
				LinkedList<TaskType> pot = new LinkedList<TaskType>();
				pot.add(SQUARE);
				pot.add(DIAGONAL);
				pot.add(ROUND);
				
				//delete all from pot that have been executed already
				// after that: pot contains all non executed
				for(TaskType t : alreadyExecutedTasks){
					pot.remove(t);
				}
				
				//select one of the remaining tasks randomly
				TaskType t = pot.get((int)Math.floor(Math.random()*pot.size()));
				
				//start selected task
				showInstructionsDialog();
				startNewTask(t); 
				alreadyExecutedTasks.add(t);

			}
		}
	}
	
	private void showInstructionsDialog(){
		//open start dialog
		SwingUtilities.invokeLater(
			new Runnable() {
		     	public void run() {
		     		JOptionPane.showMessageDialog(
			    			  getMainJFrame(), 
			    			  "Goal of this task is to follow the line with the mouse cursor as precicly as possible. " +
			    				"\n\nPlease follow these steps:" +
			    				"\n(1) CLICK on the RED square (it will turn green afterwards)." +
			    				"\n(2) FOLLOW the line with the mouse cursor." +
			    				"\n(3) When you enter the GREEN square the tasks ends automatically.", 
			    				"New Task: Instructions", 
			    				JOptionPane.INFORMATION_MESSAGE);
	      		}
	      	}
		);
	}
	
	public MainJFrame getMainJFrame(){
		return this;
	}

}
